/*! \file GraphDatabase.hpp */

#ifndef GRAPHDATABASE_HPP_INCLUDED
#define GRAPHDATABASE_HPP_INCLUDED

#include "Graph.hpp"
#include "GraphLoader.hpp"
#include "FrequentSubgraph.hpp"

#include <string>
#include <set>
#include <vector>

// include headers that implement an archive
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/set.hpp>

namespace TopologicalLearner
{
/** Contains a set of graphs and their frequent subgraphs.
 * This class contains a set of graphs and their frequent subgraphs returned by the gSpan algorithm.
 * It also contains a mapping to and from the set of semantic categories (strings) and their corresponding ID.
 * The data contained in this class may be loaded in two different ways. One way is to import the data directly from XML-files
 * and the other options is to deserialize it from an already serialized GraphDatabase object.
*/
class GraphDatabase
{



private:

    // The vector containing all the graphs in the database.
    std::vector<Graph> m_Graphs;

    std::vector<FrequentSubgraph> m_FrequentSGs;

    CategoryDegreeDist m_degreeDist;

    CategToCategDist m_catgDist;

    bool m_bUnique;

    int m_iLastCount;

    Graph BlacklistInternal
            (const Graph& G, const std::set<std::string>& sBlacklist);

    std::set<std::string> InternalGenerateBlacklist(int iThreshold);

public:

    // Internal object used to load all the graphs to and from disk.
    GraphLoader m_kLoader;

/**
 * Imports all the XML-files located in sDir.
 * The function attempts to parse all the XML-files located in a directory as graphs.
 * @param sDir A std::string of the directory to load.
 * @param iLimit Optional parameter, if specified the load will stop after iLimit graphs have been loaded.
*/
int LoadAllGraphs(std::string sDir, int iLimit = -1, bool bUnique = false);

/**
 * Loads a single graph and adds it to the graph vector
 */
bool LoadSingleGraph(std::string sDir, bool bUnique = false, std::string rootNodeName = "MITquest");

/**
 * Removes all the isolated vertices in all the graphs in the database.
*/
void RemoveIsolatedVertices();

/**
 * Finds the vertex that has a specific name (string) and returns an iterator to that vertex.
 * @param sName Semantic name of the vertex
 * @param G The graph to search for the vertex
*/
std::pair< bool, Iter_t >
        FindVertex(std::string sName, const Graph& G) const;

/**
 * Merges a set of vertices into one.
 * The function iterates through all the graphs in the database and merge the vertices in the specified set
 * into one, new vertex. This new vertex will be connected to the neighbors of the old vertices (and the old vertices are removed).
 * @param ToMerge A std::set of std::string of vertex names that are to be merged.
 * @param sNewName The name of the new vertex
 */
void MergeVertices(const std::set<std::string>& ToMerge, std::string sNewName);

/**
 * Removes a (but maintain connectivity) set of specified vertices from the database.
 * The function iterates through all the graphs in the database and removes the vertices specified.
 * It connects all the neighbors of the removed vertice to one another.
 * @param sBlacklist A std::set of std::string of vertex names that are to be removed.
 */
void Blacklist(const std::set<std::string>& sBlacklist);

    // Serializes all the graphs and the clustering as well as correlation corefficients to disk
/**
 * Serializes the class to a specified Archive.
 * This function uses boost serialization to serialize the class and all its data to disk.
 * @param ar The archive to which we will save the class to.
*/
template<class Archive>
void serialize(Archive &ar, const unsigned int version);

/**
 * Returns the graph with the specified ID.
*/
const Graph& GetGraph(int iID) const { return m_Graphs[iID]; }

/**
 * Returns the number of graphs in the database.
*/
int GetNumGraphs() const { return m_Graphs.size(); }

/**
 * Returns a const vector of all the graphs in the database.
*/
const std::vector<Graph>& GetGraphVector() const;

int GetGraphNameFromID(std::string sName);

/**
 * Sets the vector of all the graphs in the database.
*/
void SetGraphVector(std::vector<Graph> graphs) { m_Graphs = graphs; }

/**
 * Returns the unique ID of a semantic category if found, otherwise returns UINT_MAX.
 */
unsigned int GetVertexIDFromString(std::string sName) const;

/**
 * Saves all the loaded graph in this graph database to disk.
*/
void Save(std::string sFilename);

/**
 * Loads all the loaded graphs in this graph database to disk-
*/
void Load(std::string sFilename);

/**
 * Returns the string of a vertex id
 */
std::string GetStringFromVertexID(unsigned int iID) const;

/**
 * Returns a vector of all the frequent subgraphs of the database that are
 * occuring in the specified graph G
 * @return A vector with the frequent subgraphs (of the database) that are in G.
 */
std::set< std::pair< const FrequentSubgraph*, VertexMappings > >
 GetOccuringFrequentSubgraphs(const Graph& G, unsigned int iMinSize) const;

/**
 * This function generates all the frequent subgraphs above the given frequency threshold.
 * It calls the gSpan function and stores the results internally.
 * @param dFreq The frequency threshold (% of graphs that contains the subgraph)
 */
void GenerateFrequentSubgraphs(double dFreq);

void ReplaceCategory(std::string oldid, std::string newid);

/**
  * Load frequent subgraphs for this graph database from file
  * @param filename is the file output produced by gSpan algorithm
  */
//bool LoadFrequentSubgraphs(std::string filename);
/**
 * Removes all the graphs that are not connected from the database.
 */
void RemoveDisconnectedGraphs();

/**
 * Generates all the category degree distributions and stores them internally.
 */
void GenerateCategoryDegreeDist();

/**
 *  Exports the degree distribution of a specific category to file
 * The first number in the file is the degree and then it is tab delimited with the probability of that degree
 */
void ExportCategoryDist(int iID, std::string sFilename);

/**
 * Returns a const reference to the frequent subgraph vector
 */
const std::vector<FrequentSubgraph>& GetFrequentSubgraphVector() { return m_FrequentSGs; }

/**
 * Returns a const reference to the category-degree distribution
 */
CategoryDegreeDist& GetDegreeDist() { return m_degreeDist; }

CategToCategDist& GetCatgToCatgDist() { return m_catgDist; }

/**
 * Generate the category to category distributions.
 */
void GenerateCatgToCatgDist();

/**
 * Calculates the global cluster coefficient of each graph and then sums and divides by the number of graphs.
 * To the file, the cluster coefficient of each graph in the graph database is saved.
 */
float GetAverageClusterCoeff(std::string sFilename) const;

void ExportClusterCoeffDistForCategory(std::string sFilename, std::string sCategory) const;


float ExportGraphStatistics(std::string sFilename);

float GetAverageClusterCoeffForCategory(std::string sFilename, std::string sCategory);

/**
 * Returns true if the vertex labels are unique
 */
bool IsUnique() const { return m_bUnique; }

bool SetUniqueness(bool isUnique) { m_bUnique = isUnique; }

std::vector<std::string> GetGraphFilenameVector() { return m_kLoader.m_GraphFilenames; }

float GetAverageClusterCoeffForCategory(std::string sCategory);

void ExportAveDegreesAvgCluster(std::string sFilename);

std::vector<Graph> SegmentGraph(const Graph& G, std::set<int> iCentralIDs, int iThreshold = -1);

void RemoveGraphsBasedOnSize(int threshold);

void ReplaceCategories(std::map<int, int> replacementMap, Graph& G);
void MergeCentralNodes(int iThreshold,  int newVertexName);

void BlacklistOnCriterion(int iThreshold);

void ExportGraphsToDot(std::string path);

friend class GraphLoader;
friend class GraphFunctions;

};



}

#endif
